package com.cheer.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cheer.bo.*;
import com.cheer.common.ResultEnum;
import com.cheer.constant.OrgOfficeConstant;
import com.cheer.dao.ExMatchHistoryDao;
import com.cheer.dao.ExMatchQuestionDao;
import com.cheer.dao.ExMatchUserDao;
import com.cheer.dao.OaUserDao;
import com.cheer.dto.MatchResultDTO;
import com.cheer.entity.ExMatchHistoryEntity;
import com.cheer.entity.ExMatchQuestionEntity;
import com.cheer.entity.ExMatchUserEntity;
import com.cheer.entity.OaUserEntity;
import com.cheer.exception.ServiceException;
import com.cheer.service.AuthService;
import com.cheer.service.MatchService;
import com.cheer.service.OaIntegralService;
import com.cheer.util.ExcelsUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

import static com.cheer.constant.MatchConstant.*;

/**
 * @author cheer
 */
@Service
@Slf4j
public class MatchServiceImpl implements MatchService, ApplicationListener<ApplicationReadyEvent> {

    /**
     * 题库本地存储
     */
    private List<QuestionBO> questionList = new ArrayList<>();

    private List<Integer> singleQuestionIdList = new ArrayList<>();

    private List<Integer> multiQuestionIdList = new ArrayList<>();

    @Autowired
    private ExMatchQuestionDao exMatchQuestionDao;

    @Autowired
    private ExMatchUserDao exMatchUserDao;

    @Autowired
    private OaUserDao oaUserDao;

    @Autowired
    private ExMatchHistoryDao exMatchHistoryDao;

    @Autowired
    private OaIntegralService oaIntegralService;


    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        List<ExMatchQuestionEntity> questionList = exMatchQuestionDao.selectList(new QueryWrapper<>());
        for (int i = 0; i < questionList.size(); i++) {
            ExMatchQuestionEntity question = questionList.get(i);
            this.questionList.add(convertToQuestionBO(question));
            if (Objects.equals(SINGLE, question.getType())) {
                singleQuestionIdList.add(i);
            } else if (Objects.equals(MULTI, question.getType())) {
                multiQuestionIdList.add(i);
            }
        }
    }

    private QuestionBO convertToQuestionBO(ExMatchQuestionEntity question) {
        if (question == null) {
            throw new ServiceException("question init failed");
        }

        if (question.getType() == SINGLE) {

            SingleQuestionBO questionBO = new SingleQuestionBO();
            questionBO.setTitle(question.getContent());
            questionBO.setContent(Arrays.stream(StringUtils.split(question.getOption(), "#"))
                    .map(option -> new OptionBO().setTitle(option.substring(1))).collect(Collectors.toList()));
            questionBO.setAnswer(String.valueOf((char) (question.getAnswer().charAt(0) - 17)));
            return questionBO;

        } else if (question.getType() == MULTI) {

            MultiQuestionBO questionBO = new MultiQuestionBO();
            questionBO.setTitle(question.getContent());
            questionBO.setContent(Arrays.stream(StringUtils.split(question.getOption(), "#"))
                    .map(option -> new OptionBO().setTitle(option.substring(1))).collect(Collectors.toList()));
            List<Integer> answer = new ArrayList<>();
            for (char c : question.getAnswer().toCharArray()) {
                answer.add(Integer.valueOf(String.valueOf((char) (c - 17))));
            }
            questionBO.setAnswer(answer);
            return questionBO;
        }

        throw new ServiceException("question init failed, question type invalid");
    }

    @Override
    public MatchHomeBO getMatchHome(Long userId) {
        Date date = new Date();
        Date start = DateUtil.beginOfDay(date);
        Date end = DateUtil.endOfDay(date);

        List<ExMatchHistoryEntity> histories = exMatchHistoryDao.selectList(new QueryWrapper<ExMatchHistoryEntity>()
                .select("type")
                .eq("user_id", userId)
                .ge("create_time", start)
                .le("create_time", end));

        int challengeCount = 0;
        int matchCount = 0;

        for (ExMatchHistoryEntity history : histories) {
            if (history.getType() == CHALLENGE_TYPE) {
                challengeCount++;
            } else if (history.getType() == MATCH_TYPE) {
                matchCount++;
            }
        }

        MatchHomeBO matchHomeBO = new MatchHomeBO();
        if (challengeCount >= MATCH_COUNT) {
            matchHomeBO.setChallengeRemain(0);
        } else {
            matchHomeBO.setChallengeRemain(MATCH_COUNT - challengeCount);
        }
        if (matchCount >= MATCH_COUNT) {
            matchHomeBO.setMatchRemain(0);
        } else {
            matchHomeBO.setMatchRemain(MATCH_COUNT - matchCount);
        }

        return matchHomeBO;
    }

    @Override
    public MatchBO startMatch(Long userId, Integer type) {
        MatchHomeBO matchHomeBO = getMatchHome(userId);
        if (type == CHALLENGE_TYPE) {
            if (matchHomeBO.getChallengeRemain() == 0) {
                throw new ServiceException(ResultEnum.START_LIMIT);
            }
            List<QuestionBO> questionBOList = getQuestions();

            ExMatchHistoryEntity matchHistory = new ExMatchHistoryEntity();
            matchHistory.setUserId(userId);
            matchHistory.setType(type);
            exMatchHistoryDao.insert(matchHistory);

            return new MatchBO()
                    .setMatchId(matchHistory.getId())
                    .setQuestionList(questionBOList);

        } else if (type == MATCH_TYPE) {
            if (matchHomeBO.getMatchRemain() == 0) {
                throw new ServiceException(ResultEnum.START_LIMIT);
            }
            List<QuestionBO> questionBOList = getQuestions();

            ExMatchUserEntity user = exMatchUserDao.selectById(userId);
            if (user == null) {
                throw new ServiceException("用户不存在");
            }

            OpponentBO self = new OpponentBO()
                    .setUsername(user.getUsername())
                    .setHeadIcon(user.getHeadIcon())
                    .setLevel(user.getLevel());

            OpponentBO opponent = randomOpponent(self);

            ExMatchHistoryEntity matchHistory = new ExMatchHistoryEntity();
            matchHistory.setUserId(userId);
            matchHistory.setType(type);
            exMatchHistoryDao.insert(matchHistory);

            return new MatchBO()
                    .setMatchId(matchHistory.getId())
                    .setSelf(self)
                    .setOpponent(opponent)
                    .setQuestionList(questionBOList);
        }

        throw new ServiceException("比赛类型不存在");
    }

    @Autowired
    private AuthService authService;

    private OpponentBO randomOpponent(OpponentBO self) {
        Integer maxId = oaUserDao.selectMaxId();

        OaUserEntity user;

        while (true) {
            OaUserEntity randomUser = oaUserDao.selectOne(new QueryWrapper<OaUserEntity>()
                    .select("openid", "name", "headimgurl")
                    .ge("id", RandomUtil.randomInt(1, maxId))
                    .last("limit 1"));

            if (randomUser == null) {
                continue;
            }

            String image = authService.getUserImage(randomUser.getOpenid());

            if (image != null) {
                randomUser.setHeadimgurl(image);
            }

            if (!StringUtils.equals(randomUser.getHeadimgurl(), self.getHeadIcon())) {
                user = randomUser;
                break;
            }
        }

        OpponentBO opponentBO = new OpponentBO()
                .setUsername(user.getName())
                .setHeadIcon(randomHeadIcon())
                .setLevel(self.getLevel());

        int seed = opponentBO.getLevel();
        if (opponentBO.getLevel() >= 10) {
            seed = 9;
        }
        opponentBO.setCorrectCount(RandomUtil.randomInt(seed, 11));

        return opponentBO;
    }

    private String randomHeadIcon() {

        String baseUrl = "http://cdn.ithyxy.com/images/avatar"+RandomUtil.randomInt(1,16)+".png";
        return baseUrl;
    }

    @Override
    public List<QuestionBO> getQuestions() {
        List<QuestionBO> questionBOList = new ArrayList<>(10);
        // 生成比赛题目id列表
        List<Integer> singleQuestionIdList = new ArrayList<>(this.singleQuestionIdList);
        Collections.shuffle(singleQuestionIdList);

        if(singleQuestionIdList.size() > 10){
            for (Integer questionId : singleQuestionIdList.subList(0, 10)) {
                questionBOList.add(questionList.get(questionId));
            }
        }else{
            for (Integer questionId : singleQuestionIdList.subList(0, singleQuestionIdList.size())) {
                questionBOList.add(questionList.get(questionId));
            }
        }


        return questionBOList;
    }

    @Override
    public List<QuestionBO> getQuestions(Integer start) {
        // 题号从1开始，数组从0开始，所以进行一下转换
        int from = start - 1;

        if (from >= this.singleQuestionIdList.size()) {
            return new ArrayList<>();
        }

        int to = Math.min(from + 10, this.singleQuestionIdList.size());

        List<QuestionBO> questionBOList = new ArrayList<>(10);

        for (int i = from; i < to; i++) {
            questionBOList.add(questionList.get(i));
        }

        return questionBOList;
    }

    @Override
    @Transactional
    public MatchResultBO endMatch(MatchResultDTO matchResultDTO, Long userId) {
        ExMatchUserEntity user = exMatchUserDao.selectById(userId);
        if (user == null) {
            throw new ServiceException("用户不存在");
        }

        // 比赛记录写入数据库
        ExMatchHistoryEntity matchHistory = exMatchHistoryDao.selectById(matchResultDTO.getMatchId());
        if (matchHistory == null) {
            throw new ServiceException("比赛不存在");
        }

        ExMatchHistoryEntity updateMatchHistory = new ExMatchHistoryEntity();
        updateMatchHistory.setId(matchResultDTO.getMatchId());
        updateMatchHistory.setIsWin(matchResultDTO.getIsWin());
        updateMatchHistory.setCorrectNumber(matchResultDTO.getCorrectNumber());
        updateMatchHistory.setPoints(matchResultDTO.getPoints());
        exMatchHistoryDao.updateById(updateMatchHistory);

        // 更新用户成绩
        if (matchHistory.getType() == CHALLENGE_TYPE) {
            int lotteryToken = 0;

            if (matchResultDTO.getPoints() >= 80 && matchResultDTO.getPoints() < 100) {
                lotteryToken = lotteryToken + 1;
            } else if (matchResultDTO.getPoints() == 100) {
                lotteryToken = lotteryToken + 2;
            }

            if (lotteryToken > 0) {
                ExMatchUserEntity updateUser = new ExMatchUserEntity();
                updateUser.setId(userId);
                updateUser.setLotteryToken(user.getLotteryToken() + lotteryToken);
                exMatchUserDao.updateById(updateUser);
            }

            return new MatchResultBO()
                    .setLotteryToken(lotteryToken)
                    .setTotalLotteryToken(user.getLotteryToken() + lotteryToken);

        } else if (matchHistory.getType() == MATCH_TYPE) {
            int exp = 0;
            int level = 0;
            int lotteryToken = 0;

            if (matchResultDTO.getIsWin()) {
                ExMatchUserEntity updateUser = new ExMatchUserEntity();
                updateUser.setId(userId);

                exp = exp + 5;
                updateUser.setExp(user.getExp() + exp);

                if (updateUser.getExp() % 50 == 0) {
                    level = user.getLevel() + 1;
                    updateUser.setLevel(level);

                    lotteryToken += 6;
                    updateUser.setLotteryToken(user.getLotteryToken() + lotteryToken);
                } else {

                    lotteryToken += 1;
                    updateUser.setLotteryToken(user.getLotteryToken() + lotteryToken);
                }
                exMatchUserDao.updateById(updateUser);
            }

            return new MatchResultBO()
                    .setExp(exp)
                    .setLevel(level)
                    .setLotteryToken(lotteryToken)
                    .setTotalLotteryToken(user.getLotteryToken() + lotteryToken);
        }

        throw new ServiceException("比赛类型不存在");
    }

    @Override
    public MatchRecordBO getRecord(Long userId) {
        MatchRecordBO matchRecordBO = new MatchRecordBO();

        Date date = new Date();
        Date start = DateUtil.beginOfDay(date);
        Date end = DateUtil.endOfDay(date);

        List<ExMatchHistoryEntity> histories = exMatchHistoryDao.selectList(new QueryWrapper<ExMatchHistoryEntity>()
                .eq("user_id", userId)
                .ge("create_time", start)
                .le("create_time", end)
                .orderByAsc("create_time"));

        List<MatchHistoryWithScoreBO> challengeResultBOList = new ArrayList<>();
        List<MatchHistoryWithScoreBO> matchResultBOList = new ArrayList<>();

        for (ExMatchHistoryEntity history : histories) {
            if (history.getType() == CHALLENGE_TYPE) {
                challengeResultBOList.add(new MatchHistoryWithScoreBO()
                        .setScore(history.getPoints())
                        .setCorrectNumber(history.getCorrectNumber()));
            } else if (history.getType() == MATCH_TYPE) {
                matchResultBOList.add(new MatchHistoryWithScoreBO()
                        .setIsWin(history.getIsWin())
                        .setScore(history.getPoints())
                        .setCorrectNumber(history.getCorrectNumber()));
            }
        }

        matchRecordBO.setChallengeResultList(challengeResultBOList)
                .setMatchResultList(matchResultBOList);
        return matchRecordBO;
    }

    @Override
    public void exportMatchHistory() {
        List<Map<String, Object>> excelList = new ArrayList<>();
        Map<String, Object> header = new HashMap<>();
        String sheet = "参与情况";
        header.put("sheetName", sheet);
        excelList.add(header);

        for (int i = 0; i < OrgOfficeConstant.organization.length; i++) {
            for (int j = 0; j < OrgOfficeConstant.office[i].length; j++) {

                int organization = i;
                int office = j + 1;

                if (i == OrgOfficeConstant.organization.length - 1 && j == OrgOfficeConstant.office[i].length - 1) {
                    office = 100;
                }

                Integer count = exMatchUserDao.selectCount(new QueryWrapper<ExMatchUserEntity>()
                        .eq("organization", organization)
                        .eq("office", office));

                Integer mat = exMatchHistoryDao.selectCountByOrg(organization, office);

                Map<String, Object> line = new HashMap<>();
                line.put("org", OrgOfficeConstant.organization[i] + "-" + OrgOfficeConstant.office[i][j]);
                line.put("reg", count);
                line.put("mat", mat);
                excelList.add(line);
            }
        }

        String[] columnNames = {"单位", "注册人数", "参与人数"};
        String[] keys = {"org", "reg", "mat"};
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        ExcelsUtil.ExcelSingleOutputStream(excelList, keys, columnNames, sheet, request, response);
    }

    /*@Override
    public void exportVideoHistory() {

        List<Map<String, Object>> excelList = new ArrayList<>();
        Map<String, Object> header = new HashMap<>();
        String sheet = "参与情况";
        header.put("sheetName", sheet);
        excelList.add(header);

        List<Map<String, String>> maps = exMatchHistoryDao.select2Org();

        for (int i = 0; i < maps.size(); i++) {

            String name = maps.get(i).get("name");
            String wholePath = maps.get(i).get("wholePath");
            Integer count = exMatchHistoryDao.selectCountVideoByOrg(wholePath);
            Integer mat = exMatchHistoryDao.selectCountMatByOrg(wholePath);
            if(mat == null){
                mat = 0;
            }
            Map<String, Object> line = new HashMap<>();
                line.put("org", getWholePath(wholePath.split(",")));
                line.put("reg", count);
                line.put("mat", mat);
                excelList.add(line);
        }

        String[] columnNames = {"单位", "单位-参与人数", "单位点赞总数"};
        String[] keys = {"org", "reg", "mat"};
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        ExcelsUtil.ExcelSingleOutputStream(excelList, keys, columnNames, sheet, request, response);

    }

    public String getWholePath(String[] split){

        String wholeOrgName = "";
        for (int i = 0; i <split.length; i++) {
            String orgName = exMatchHistoryDao.selectPathById(split[i]);
            wholeOrgName +=orgName+"-";
        }
        return wholeOrgName.substring(0, wholeOrgName.length() - 1);

    }*/



}
